﻿using System.Reflection;
using Autofac;
using Autofac.Core;
using Autofac.Extras.DynamicProxy;
using AutoMapper;
using Common.Abstraction;
using Common.Autofac.Aop;
using Common.Cache;
using Common.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using AutoMapAttribute = AutoMapper.AutoMapAttribute;
using Module = Autofac.Module;

namespace Common.Autofac;

/// <summary>
/// autofac ioc注册模块
/// </summary>
public class AutofacModule : Module
{
    private readonly IServiceCollection _service;

    private readonly IConfiguration _configuration;

    // private readonly Assembly _assembly;
    private readonly ILogger<AutofacModule>? _logger;

    private readonly List<Assembly> _assemblies = new List<Assembly>();

    private static readonly Type AutoMapType = typeof(AutoMapAttribute);

    public AutofacModule(IServiceCollection service, IConfiguration configuration, IEnumerable<Assembly> assemblies)
    {
        _service = service;
        _configuration = configuration;
        _logger = _service.BuildServiceProvider().GetService<ILogger<AutofacModule>>();
        // _assembly = typeof(Program).Assembly;
        _assemblies.AddRange(assemblies);
    }

    /// <summary>
    /// 向ioc容器注册类型或实例
    /// </summary>
    /// <param name="builder"></param>
    protected override void Load(ContainerBuilder builder)
    {
        // builder.RegisterBuildCallback(scope => { });


        // 注册aop拦截器
        builder.RegisterType<GlobalInterceptor>().InstancePerLifetimeScope();

        foreach (var assembly in _assemblies)
        {
            BindProperties(builder, assembly);
        }

        BindAutoMapper(builder);

        RegisterTypes(builder);
        RegisterRedis(builder);

        RegisterRestClient(builder);
    }

    /// <summary>
    /// 注册restClient
    /// </summary>
    /// <param name="builder"></param>
    private void RegisterRestClient(ContainerBuilder builder)
    {
        
    }

    private void BindAutoMapper(ContainerBuilder builder)
    {
        var configuration = new MapperConfiguration(cfg =>
            // cfg.AddProfile()
            cfg.AddMaps(_assemblies));

        var mapper = new Mapper(configuration);
        builder.RegisterInstance(mapper).AsImplementedInterfaces();
    }

    private void RegisterRedis(ContainerBuilder builder)
    {
        builder.Register(ctx =>
        {
            var redisConfig = ctx.Resolve<RedisConfig>();
            // var redisConfig = redisOptions?.Value;
            var password = string.IsNullOrWhiteSpace(redisConfig.Auth) ? "" : $",password={redisConfig.Auth}";
            // 127.0.0.1:16379,defaultDatabase=2,password=asdd8s7w5ada9t
            var redisConnection = ConnectionMultiplexer.Connect($"{redisConfig.Host}:{redisConfig.Port},{password}");
            var redisDb = redisConnection.GetDatabase(redisConfig.Database);
            return redisDb;
            // builder.RegisterInstance(redisDb);
        }).SingleInstance();
    }

    private void RegisterTypes(ContainerBuilder builder)
    {
        // 注册CacheManager
        builder.RegisterType<MemoryCacheManager>().As<ICacheManager>();
        builder.RegisterType<RedisCacheManager>().As<ICacheManager>();


        // 注册Repository
        var repositoryGenericType = typeof(RepositoryBase<,,>);
        var serviceType = typeof(IService);

        // 注册服务
        bool IsServiceType(Type t) => t.IsClass && serviceType.IsAssignableFrom(t);

        builder.RegisterAssemblyTypes(_assemblies.ToArray())
            .Where(it => it != repositoryGenericType && it.BaseType is { IsGenericType: true } &&
                         repositoryGenericType.IsAssignableTo(it.BaseType.GetGenericTypeDefinition()))
            .PropertiesAutowired(new AutowiredPropertySelector());
        
        // TODO 要自己分析出IService的实现类是否实现别的接口
        foreach (var assembly in _assemblies)
        {
            var enumerable = assembly.GetTypes().Where(IsServiceType);
            foreach (var type in enumerable)
            {
                _logger.LogInformation("service type: {@type}", type);
            }
        }
    
        builder.RegisterAssemblyTypes(_assemblies.ToArray()).Where(IsServiceType)
            .AsSelf()
            .EnableClassInterceptors()
            // .EnableInterfaceInterceptors()
            .PropertiesAutowired();

        // 获取所有控制器类型并使用属性注入
    }

    private void BindProperties(ContainerBuilder builder, Assembly assembly)
    {
        var optionSectionType = typeof(ConfigurationPropertiesAttribute);
        var types = assembly.GetTypes().Where(it =>
                it.IsClass &&
                it.IsDefined(optionSectionType, true))
            .ToList();

        _service.AddOptions();

        foreach (var type in types)
        {
            var optionSection = type.GetCustomAttribute<ConfigurationPropertiesAttribute>(true);
            // optionSection.Prefix
            if (string.IsNullOrWhiteSpace(optionSection?.Prefix)) continue;
            var configInstance = Activator.CreateInstance(type);
            if (configInstance == null) continue;
            _configuration.GetSection(optionSection.Prefix).Bind(configInstance);

            builder.RegisterInstance(configInstance).AsSelf().AsImplementedInterfaces();
        }
    }


    /// <summary>
    /// 属性注入选择器
    /// </summary>
    private class AutowiredPropertySelector : IPropertySelector
    {
        public bool InjectProperty(PropertyInfo propertyInfo, object instance)
        {
            // 带有 AutowiredAttribute 特性的属性会进行属性注入
            return propertyInfo.CustomAttributes.Any(it => it.AttributeType
                                                           == typeof(AutowiredAttribute));
        }
    }
}